#!/usr/bin/env bash

__rvm_git_clean_repo()
{
  \command \git checkout -f master
  \command \git reset --hard HEAD
  \command \rm -fr .git/rebase-apply
}

__rvm_fetch_ruby()
{
  \typeset _current_command

  if (( ${rvm_ruby_selected_flag:=0} == 0 ))
  then __rvm_select
  fi

  if
    (( ${rvm_head_flag:=0} == 0 )) &&
    [[ -z "${rvm_ruby_tag:-}" && -z "${rvm_ruby_revision:-}" && -z "${rvm_ruby_sha:-}"  && -z "${rvm_ruby_repo_tag:-}" ]]
  then
    __rvm_fetch_ruby_package || return $?
  elif [[ "${rvm_ruby_interpreter}" == "truffleruby" ]]; then
    # Always use __rvm_fetch_ruby_package() for TruffleRuby, building from the repository is not supported in RVM
    __rvm_fetch_ruby_package || return $?
  else
    \typeset result=0

    mkdir -p "${rvm_repos_path}/${rvm_ruby_interpreter}"
    true ${rvm_ruby_url:="$rvm_ruby_repo_url"}

    if
      echo "$rvm_ruby_url" | __rvm_grep 'git' >/dev/null 2>&1
    then
      __rvm_fetch_ruby_head_git || return $?
    else
      __rvm_fetch_ruby_head_svn || return $?
    fi

    rvm_log "Copying from repo to src path..."

    __rvm_rm_rf "${rvm_src_path}/$rvm_ruby_string"
    __rvm_cp -R "${rvm_repos_path}/${rvm_ruby_interpreter}" "${rvm_src_path}/$rvm_ruby_string"

    return ${result:-0}
  fi
}

__rvm_fetch_ruby_cleanup()
{
  if
    (( ${rvm_head_flag:=0} == 0 )) &&
    [[ -z "${rvm_ruby_tag:-}" && -z "${rvm_ruby_revision:-}" && -z "${rvm_ruby_sha:-}" && -z "${rvm_ruby_repo_tag:-}" ]]
  then
    true # nothing to cleanup
  else
    __rvm_rm_rf "${rvm_src_path}/$rvm_ruby_string"/.git
    __rvm_rm_rf "${rvm_src_path}/$rvm_ruby_string"/.svn
  fi
}

__rvm_fetch_ruby_package()
{
    rvm_ruby_package_name="${rvm_ruby_package_name:-"$rvm_ruby_string"}"
    rvm_ruby_package_file="${rvm_ruby_package_file:-"$rvm_ruby_package_name"}"

    case "$rvm_ruby_string" in
      (ruby-1.8.4*) rvm_archive_extension="${rvm_archive_extension:-tar.gz}"  ;;
      (ruby-*)      rvm_archive_extension="${rvm_archive_extension:-tar.bz2}" ;;
      (*)           rvm_archive_extension="${rvm_archive_extension:-tar.gz}"  ;;
    esac

    case "$rvm_ruby_interpreter" in
      (ruby)
        rvm_ruby_url="$(__rvm_db "${rvm_ruby_interpreter}_url")/${rvm_ruby_release_version}.${rvm_ruby_major_version}/$rvm_ruby_package_file.$rvm_archive_extension"
        ;;
      (ree)
        rvm_ruby_url="$(__rvm_db "${rvm_ruby_interpreter}_${rvm_ruby_version}_url")/${rvm_ruby_package_file}.${rvm_archive_extension}"
        ;;
      (jruby)
        rvm_error "Trying to compile jruby from binary package - this is a bug, please report to RVM."
        return 198
        ;;
      (maglev|rubinius|rbx|truffleruby)
        true # Should already be set from scripts/functions/selector_interpreters
        ;;
      (*)
        rvm_ruby_url="$(__rvm_db "${rvm_ruby_interpreter}_url")/${rvm_ruby_package_file}.${rvm_archive_extension}"
        ;;
    esac

    rvm_ruby_package_file_ext="${rvm_ruby_package_file}.${rvm_archive_extension}"

    rvm_log "$rvm_ruby_string - #downloading ${rvm_ruby_package_file}, this may take a while depending on your connection..."
    "$rvm_scripts_path/fetch" "${rvm_ruby_url}" "${rvm_ruby_package_file_ext}" || return $?

    # Remove the directory if it is empty -- empty how?
    [[ -d "${rvm_src_path}/$rvm_ruby_string" ]] && rmdir "${rvm_src_path}/$rvm_ruby_string" 2>/dev/null || true

    if
      [[ ! -d "${rvm_src_path}/$rvm_ruby_string" ]]
    then
      mkdir -p "${rvm_tmp_path:-/tmp}/rvm_src_$$"

      __rvm_log_command "extract" "$rvm_ruby_string - #extracting $rvm_ruby_package_file to ${rvm_src_path}/$rvm_ruby_string" \
        __rvm_package_extract "${rvm_archives_path}/${rvm_ruby_package_file_ext}" "${rvm_tmp_path:-/tmp}/rvm_src_$$" ||
      case $? in
        199)
          rvm_error "\nUnrecognized archive format '$archive_format'"
          return 199
          ;;
        *)
          rvm_error "There has been an error while trying to extract the source. Halting the installation."
          return 1
          ;;
      esac

      __rvm_rm_rf "${rvm_src_path}/$rvm_ruby_string"

      \command \mv "$(
        __rvm_find ${rvm_tmp_path:-/tmp}/rvm_src_$$ -mindepth 1 -maxdepth 1 -type d
      )" "${rvm_src_path}/$rvm_ruby_string"

      __rvm_rm_rf "${rvm_tmp_path:-/tmp}/rvm_src_$$"

      if
        [[ -n "${rvm_ruby_name:-""}" && -d "${rvm_src_path}/$(echo $rvm_ruby_string | __rvm_sed -e 's/-n.*//')" ]]
      then
        \command \mv "${rvm_src_path}/$(echo "$rvm_ruby_string" | __rvm_sed -e 's/-n.*//')" "${rvm_src_path}/$rvm_ruby_string"
      fi
    else
      rvm_log "$rvm_ruby_string - #already extracted to ${rvm_src_path}/$rvm_ruby_string"
    fi

    true # for osx
}

__rvm_fetch_ruby_head_git()
{
      case "$rvm_ruby_interpreter" in
        ruby)
          # Determine Branch
          if [[ -z "${rvm_ruby_repo_branch:-}" ]]
          then
            if [[ -n "${rvm_ruby_major_version:-}" ]]
            then
              if
                [[ -n "${rvm_ruby_minor_version:-}" ]] &&
                __rvm_version_compare "${rvm_ruby_version}" -lt 2.1.0
              then
                rvm_ruby_repo_branch="ruby_${rvm_ruby_release_version:-1}_${rvm_ruby_major_version}_${rvm_ruby_minor_version}"
              else
                rvm_ruby_repo_branch="ruby_${rvm_ruby_release_version:-1}_${rvm_ruby_major_version}"
              fi
            else
              rvm_ruby_repo_branch="master" # NOTE: Ruby Core team maps 'master' as HEAD
            fi
          fi
          ;;

        *)
          rvm_ruby_repo_branch="${rvm_ruby_repo_branch:-"master"}"
          ;;

      esac

      # Clone if repository does not yet exist locally
      if
        [[ -d "${rvm_repos_path}/${rvm_ruby_interpreter}/.git" ]]
      then
        (
          __rvm_cd "${rvm_repos_path}/${rvm_ruby_interpreter}"
          \typeset current_url
          current_url="$(\command \git remote -v | __rvm_awk '$1=="origin" && $3=="(fetch)" {print $2}')"
          [[ "$current_url" == "$rvm_ruby_repo_url" ]] || \command \git remote set-url origin "$rvm_ruby_repo_url"
        )
      else
        __rvm_rm_rf "${rvm_repos_path}/${rvm_ruby_interpreter}"

        rvm_ruby_repo_http_url="${rvm_ruby_repo_url//git:/https:}"

        \typeset git_clone_options
        git_clone_options=()
        # do not use '--depth 1' be default, we need to allow getting different commits
        if [[ -n "${rvm_git_clone_depth:-}" ]]
        then git_clone_options+=( --depth ${rvm_git_clone_depth} )
        fi
        __rvm_log_command "git.clone.git" \
          "Cloning from $rvm_ruby_repo_url, this may take a while depending on your connection" \
          \command \git clone "${git_clone_options[@]}" "$rvm_ruby_repo_url"      "${rvm_repos_path}/${rvm_ruby_interpreter}" ||
        __rvm_log_command "git.clone.http" \
          "Cloning from $rvm_ruby_repo_http_url, this may take a while depending on your connection" \
          \command \git clone "${git_clone_options[@]}" "$rvm_ruby_repo_http_url" "${rvm_repos_path}/${rvm_ruby_interpreter}" ||
        return $?
      fi

      # Use the selected branch.
      (
        __rvm_cd "${rvm_repos_path}/${rvm_ruby_interpreter}"

        remote="${remote:-origin}"
        branch=$(\command \git symbolic-ref -q HEAD 2>/dev/null)
        branch=${branch##refs/heads/}
        tag=$(\command \git describe --tags 2>/dev/null)

        # Ensure we are in a good state.
        \command \git reset --hard HEAD
        # just in case fix the fetch for the remote, new git restricts it to master
        \command \git config "remote.${remote}.fetch" "+refs/heads/*:refs/remotes/${remote}/*"
        # Download the latest updates locally.
        \command \git fetch --tags "${remote}"
        if [[ -n "${rvm_ruby_repo_tag:-}" ]]
        then
          if [[ "$tag" != "${rvm_ruby_repo_tag}" ]]
          then
            \command \git checkout -f "${rvm_ruby_repo_tag}"
          fi
          \command \git pull "$remote" "${rvm_ruby_repo_tag}" # Bring local to latest
        fi ||
        {
          result=$?
          rvm_error "There has been an error while checking out tag ${rvm_ruby_repo_tag}.  \nHalting the installation."
          return $result
        }

        if
          [[ "$branch" == "${rvm_ruby_repo_branch}" ]]
        then
          \command \git pull "${remote}" "${rvm_ruby_repo_branch}"
        else
          case "$(git branch 2>/dev/null)" in
            (*[[:space:]]${rvm_ruby_repo_branch}*)
              # Not already on the desired branch, but it does exist locally.
              \command \git checkout -f "${rvm_ruby_repo_branch}" # Branch is local, checkout
              \command \git pull "$remote" "${rvm_ruby_repo_branch}" # Bring local to latest
              ;;
            (*)
              # Desired branch does not exist locally.
              \command \git checkout -f -b "${rvm_ruby_repo_branch}" -t "${remote}/${rvm_ruby_repo_branch}" ||
              {
                result=$?
                rvm_error "Branch $remote/$rvm_ruby_repo_branch not found."
                return $result
              }
              ;;
          esac
        fi ||
        {
          result=$?
          rvm_error "There has been an error while checking out branch ${rvm_ruby_repo_branch}.  \nHalting the installation."
          return $result
        }
        __rvm_fetch_from_git_revision_or_sha || return $?
      )
      true # for OSX
}

__rvm_fetch_from_git_revision_or_sha()
{
  \typeset result __from
  __from=""
  if   [[ -n "${rvm_ruby_tag:-}" ]]
  then __from="${rvm_ruby_tag#t}"
  elif [[ -n "$rvm_ruby_revision" ]]
  then __from="${rvm_ruby_revision}"
  elif [[ -n "${rvm_ruby_sha:-}" ]]
  then __from="${rvm_ruby_sha}"
  elif [[ -n "${rvm_ruby_repo_branch:-}" ]]
  then __from="${rvm_ruby_repo_branch}"
  elif [[ -n "${rvm_ruby_repo_tag:-}" ]]
  then __from="${rvm_ruby_repo_tag}"
  fi
  if
    [[ -n "$__from" ]]
  then
    if [[ "$__from" == "head" ]]
    then __from="master"
    fi
    rvm_log "git checkout $__from"
    \command \git checkout -f -q "$__from" ||
    {
      result=$?
      rvm_error "There has been an error while trying to checkout the source branch.\nHalting the installation."
      return $result
    }
  fi
}

__rvm_fetch_ruby_head_svn()
{
      if
        [[ -n "${rvm_ruby_tag:-""}" ]]
      then
        # TODO: Check if tag v is valid
        true "${rvm_ruby_url:="$rvm_ruby_repo_url/tags/$(echo "$rvm_ruby_tag" | __rvm_sed 's/^t//')"}"
      elif
        [[ -z "${rvm_ruby_version:-""}" && ${rvm_head_flag:-0} -eq 1 ]]
      then
        true "${rvm_ruby_url:="$rvm_ruby_repo_url/trunk"}"
      elif
        [[  "${rvm_ruby_major_version:-""}" == "9" ]]
      then
        if
          [[ -z "${rvm_ruby_minor_version:-""}" || "${rvm_ruby_minor_version:-""}" = 3 ]]
        then
          true "${rvm_ruby_url:="$rvm_ruby_repo_url/trunk"}"
        else
          true "${rvm_ruby_url:="$rvm_ruby_repo_url/branches/ruby_${rvm_ruby_release_version}_${rvm_ruby_major_version}_${rvm_ruby_minor_version}"}"
        fi
      elif
        [[ -z "${rvm_ruby_minor_version:-""}" ||
          "${rvm_ruby_major_version:-""}.${rvm_ruby_minor_version:-""}" = "8.8"
        ]]
      then
        true "${rvm_ruby_url:="$rvm_ruby_repo_url/branches/ruby_${rvm_ruby_release_version}_${rvm_ruby_major_version}"}"
      else
        "${rvm_ruby_url:="$rvm_ruby_repo_url/branches/ruby_${rvm_ruby_release_version}_${rvm_ruby_major_version}_${rvm_ruby_minor_version}"}"
      fi

      rvm_rev=""
      if
        [[ -n "${rvm_ruby_revision:-""}" ]]
      then
        rvm_rev="-$rvm_ruby_revision"
      fi
      (
        __rvm_cd "${rvm_repos_path}/${rvm_ruby_interpreter}"
        if
          [[ -d "${rvm_repos_path}/${rvm_ruby_interpreter}/.svn" ]]
        then
          rvm_log "Updating ruby from $rvm_ruby_url"
          __rvm_log_command "svn.switch" "Switch to $rvm_ruby_url" svn switch $rvm_ruby_url
          __rvm_log_command "svn.update" "Update svn" svn update

          if
            [[ -n "${rvm_rev:-""}" ]]
          then
            __rvm_log_command "svn.checkout" "Checking out revision ${rvm_rev/-r/-r } from $rvm_ruby_url" \
              svn update -q ${rvm_rev/-r/-r }
          fi
        else
          __rvm_rm_rf "${rvm_repos_path}/${rvm_ruby_interpreter}"
          __rvm_log_command "svn.checkout" "Downloading source from ${rvm_ruby_url}." \
            svn checkout -q ${rvm_rev/-r/-r } "$rvm_ruby_url" "${rvm_repos_path}/${rvm_ruby_interpreter}"
        fi
      )
      result=$?
      if (( result > 0 ))
      then
        rvm_error "There has been an error while trying to fetch / update the source.  \nHalting the installation."
        return $result
      fi
}
